package com.lingchou.cloud.process.client.controller;

import com.lc.common.bean.response.Result;
import com.lc.common.exception.HandlerException;
import com.lingchou.cloud.process.api.controller.ProcessOperationApi;
import com.lingchou.cloud.process.api.dto.constant.FlowConstant;
import com.lingchou.cloud.process.api.dto.param.AddSignVo;
import com.lingchou.cloud.process.api.enums.CommentTypeEnum;
import com.lingchou.cloud.process.api.enums.ProcessNodeTypeEnum;
import com.lingchou.cloud.process.client.cmd.processinstance.DeleteFlowAbleProcessInstanceCmd;
import com.lingchou.cloud.process.client.entity.DefinitionSupplementary;
import com.lingchou.cloud.process.client.service.FlowAbleBpmnModelService;
import com.lingchou.cloud.process.client.service.FlowAbleCommentService;
import com.lingchou.cloud.process.client.service.ProcessModelService;
import com.lingchou.cloud.process.client.util.ThreadLocalUtil;
import org.apache.commons.lang.StringUtils;
import org.flowable.bpmn.model.EndEvent;
import org.flowable.engine.HistoryService;
import org.flowable.engine.ManagementService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@Validated
public class ProcessOperationApiImpl implements ProcessOperationApi {
    protected Logger log = LoggerFactory.getLogger(this.getClass());
    private final TaskService taskService;
    private final RuntimeService runtimeService;
    private final ManagementService managementService;
    private final HistoryService historyService;
    private final FlowAbleCommentService flowAbleCommentService;
    private final FlowAbleBpmnModelService flowAbleBpmnModelService;
    private final ProcessModelService processModelService;

    public static final String TASK_UNDEFINED = "任务不存在";

    public ProcessOperationApiImpl(TaskService taskService, RuntimeService runtimeService, ManagementService managementService, HistoryService historyService, FlowAbleCommentService flowAbleCommentService, FlowAbleBpmnModelService flowAbleBpmnModelService, ProcessModelService processModelService) {
        this.taskService = taskService;
        this.runtimeService = runtimeService;
        this.managementService = managementService;
        this.historyService = historyService;
        this.flowAbleCommentService = flowAbleCommentService;
        this.flowAbleBpmnModelService = flowAbleBpmnModelService;
        this.processModelService = processModelService;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<String> apply(String taskId, String operator, String comment) {
        applyTask(taskId, operator, comment);
        return Result.success("processed ok!");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<String> applyForList(List<String> taskIds, String operator, String comment) {
        //一条失败 则全部返回（秦 决策）
        taskIds.forEach(taskId -> applyTask(taskId, operator, comment));
        return Result.success("processed ok!");
    }

    /**
     * 审批通过
     *
     * @param taskId   任务ID
     * @param operator 操作人
     * @param comment  评论
     */
    public void applyTask(String taskId, String operator, String comment) {
        //1.查看当前任务是存在
        TaskEntity taskEntity = (TaskEntity) taskService.createTaskQuery().taskId(taskId).singleResult();
        if (taskEntity == null) {
            throw new HandlerException("任务不存在");
        }
        //塞进ThreadLocal
        ThreadLocalUtil.putStatus(CommentTypeEnum.APPROVAL);
        //修改执行人 其实我这里就相当于签收了
        taskService.setAssignee(taskId, operator);
        //执行任务
        taskService.complete(taskId);
        //生成审批意见
        flowAbleCommentService.addComment(taskId, operator, taskEntity.getProcessInstanceId(), CommentTypeEnum.APPROVAL.toString(), comment);
    }


    @Transactional(rollbackFor = Exception.class)
    public Result<String> apply2(String taskId, String operator, String comment) {
        //1.查看当前任务是存在
        TaskEntity taskEntity = (TaskEntity) taskService.createTaskQuery().taskId(taskId).singleResult();
        if (taskEntity == null) {
            return Result.failure(TASK_UNDEFINED);
        }
        //外围声明委派任务ID
        String pendingTask = taskId;
        //塞进ThreadLocal
        ThreadLocalUtil.putStatus(CommentTypeEnum.APPROVAL);
        //2.委派处理
        if (DelegationState.PENDING.equals(taskEntity.getDelegationState())) {
            //2.1 创建子任务 并完成 生成历史记录
            TaskEntity task = processModelService.createSubTask(taskEntity, operator);
            taskService.complete(task.getId());
            pendingTask = task.getId();
            //2.2执行委派
            taskService.resolveTask(taskId);
        } else {
            //3.1修改执行人 其实我这里就相当于签收了
            taskService.setAssignee(taskId, operator);
            //3.2执行任务
            taskService.complete(taskId);
            //4.处理加签父任务
            String parentTaskId = taskEntity.getParentTaskId();
            if (StringUtils.isNotBlank(parentTaskId)) {
                String tableName = managementService.getTableName(TaskEntity.class);
                String sql = "select count(1) from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}";
                long subTaskCount = taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).count();
                if (subTaskCount == 0) {
                    Task task = taskService.createTaskQuery().taskId(parentTaskId).singleResult();
                    //处理前后加签的任务
                    taskService.resolveTask(parentTaskId);
                    if (FlowConstant.AFTER_ADDSIGN.equals(task.getScopeType())) {
                        taskService.complete(parentTaskId);
                    }
                }
            }
        }
        //5.生成审批意见
        flowAbleCommentService.addComment(pendingTask, operator, taskEntity.getProcessInstanceId(), CommentTypeEnum.APPROVAL.toString(), comment);
        return Result.success("processed ok!");
    }

    @Override
    public Result<String> reject(String taskId, String operator, String comment) {
        rejectTask(taskId, operator, comment);
        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<String> rejectForList(List<String> taskIds, String operator, String comment) {
        //一条失败 则全部返回（秦 决策）
        taskIds.forEach(taskId -> rejectTask(taskId, operator, comment));
        return Result.success();
    }

    /**
     * 审批拒绝
     *
     * @param taskId   任务ID
     * @param operator 操作人
     * @param comment  评论
     */
    public void rejectTask(String taskId, String operator, String comment) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            throw new HandlerException("任务不存在");
        }
        //塞入当前人 （因为有代理情况）
        taskService.setAssignee(taskId, operator);
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
        List<EndEvent> endNodes = flowAbleBpmnModelService.findEndFlowElement(processInstance.getProcessDefinitionId());
        if (endNodes.isEmpty()) {
            throw new HandlerException("节点异常");
        }
        //塞进ThreadLocal
        ThreadLocalUtil.putStatus(CommentTypeEnum.TURN_DOWN);
        String endId = endNodes.get(0).getId();
        //1、执行终止
        List<Execution> executions = runtimeService.createExecutionQuery().parentId(processInstance.getId()).list();
        List<String> executionIds = executions.stream().map(Execution::getId).collect(Collectors.toList());
        processModelService.moveExecutionsToSingleActivityId(executionIds, endId);
        //2、添加审批记录
        flowAbleCommentService.addComment(taskId, operator, task.getProcessInstanceId(), CommentTypeEnum.TURN_DOWN.toString(),
                comment);
    }


    @Override
    public Result addMultiInstanceExecution(String taskActivityId, String processInstanceId, List<String> assignees) {
        //此处对并签中的人员变量暂时设置为 "assignee："+taskActivityId
        Execution execution = runtimeService.addMultiInstanceExecution(taskActivityId, processInstanceId,
                Collections.singletonMap("assignee：" + taskActivityId, assignees));
        return execution == null ? Result.failure("添加失败") : Result.success();
    }

    @Override
    public Result delegateTask(String taskId, String userId, String operator, String comment) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            return Result.failure(TASK_UNDEFINED);
        }
        //审批人是当前操作人
        taskService.setAssignee(taskId, operator);
        //委派
        taskService.delegateTask(taskId, userId);
        //1.添加审批意见
        flowAbleCommentService.addComment(taskId, operator, task.getProcessInstanceId(), CommentTypeEnum.DELEGATE.toString(), comment);
        return Result.success();
    }

    @Override
    public Result turnTask(String taskId, String userId, String operator, String comment) {
        TaskEntity taskEntity = (TaskEntity) taskService.createTaskQuery().taskId(taskId).singleResult();
        if (taskEntity == null) {
            return Result.failure(TASK_UNDEFINED);
        }
        //1.生成历史记录(创建子任务并完成子任务)
        TaskEntity subTask = processModelService.createSubTask(taskEntity, operator);
        //2.添加审批意见
        flowAbleCommentService.addComment(subTask.getId(), operator, subTask.getProcessInstanceId(), CommentTypeEnum.TURN_TO.toString(), comment);
        taskService.complete(subTask.getId());
        //3.转办
        taskService.setAssignee(taskId, userId);
        taskService.setOwner(taskId, operator);
        return Result.success();
    }

    @Override
    public Result<String> deleteProcessInstanceById(String processInstanceId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (processInstance != null) {
            DeleteFlowAbleProcessInstanceCmd cmd = new DeleteFlowAbleProcessInstanceCmd(processInstanceId, "删除流程实例", true);
            managementService.executeCommand(cmd);
            return Result.success();
        }
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (historicProcessInstance != null) {
            historyService.deleteHistoricProcessInstance(processInstanceId);
            return Result.success();
        }
        return Result.failure("流程不存在");
    }

    @Override
    public Result<String> changeProcessInstanceStatusById(String processInstanceId, boolean suspension) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (processInstance == null) {
            return Result.failure("流程不存在");
        }
        if (processInstance.isSuspended() == suspension) {
            return Result.failure("已是当前状态");
        }
        if (suspension) {
            runtimeService.suspendProcessInstanceById(processInstanceId);
        } else {
            runtimeService.activateProcessInstanceById(processInstanceId);
        }
        return Result.success("操作成功");
    }

    @Override
    public Result<String> stopProcessInstance(String processInstanceId, String operator, String comment) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (processInstance != null) {
            //1、添加审批记录
            flowAbleCommentService.addComment(null, operator, processInstanceId, CommentTypeEnum.TERMINATED.toString(),
                    comment);
            List<EndEvent> endNodes = flowAbleBpmnModelService.findEndFlowElement(processInstance.getProcessDefinitionId());
            if (endNodes.isEmpty()) {
                throw new HandlerException("节点异常，找不到结束节点");
            }
            String endId = endNodes.get(0).getId();
            //2、执行终止
            List<Execution> executions = runtimeService.createExecutionQuery().parentId(processInstanceId).list();
            List<String> executionIds = executions.stream().map(Execution::getId).collect(Collectors.toList());
            processModelService.moveExecutionsToSingleActivityId(executionIds, endId);
            return Result.success();
        }
        return Result.failure("不存在运行的流程实例,请确认!");
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<String> addSignTask(AddSignVo addSignVo) {
        TaskEntity taskEntity = (TaskEntity) taskService.createTaskQuery().taskId(addSignVo.getTaskId()).singleResult();
        if (taskEntity == null) {
            return Result.failure(TASK_UNDEFINED);
        }
        //配置扩展查询
        DefinitionSupplementary definitionSupplementary = processModelService.queryDefinitionSupplementary(taskEntity.getTaskDefinitionKey());
        //根据执行器获取流程实例ID，与类型参数，作为参数查询变量值
        HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery()
                .processInstanceId(taskEntity.getProcessInstanceId())
                .variableName(definitionSupplementary.getNodeTypeParamName()).singleResult();
        String typeValue = historicVariableInstance.getValue().toString();
        if (ProcessNodeTypeEnum.OR_SIGN.name().equals(typeValue)) {
            return Result.failure("当前节点不能是或签节点");
        }
        //修改变量表里 单签 为 并签
        if (ProcessNodeTypeEnum.SINGLE.name().equals(typeValue)) {
            runtimeService.setVariable(taskEntity.getExecutionId(), definitionSupplementary.getNodeTypeParamName(), ProcessNodeTypeEnum.WITH_SIGN.name());
        }
        //节点加人
        Execution execution = runtimeService.addMultiInstanceExecution(taskEntity.getTaskDefinitionKey(), taskEntity.getProcessInstanceId(),
                Collections.singletonMap("assignee", addSignVo.getUserId()));
        if (execution == null) {
            return Result.failure("加签失败");
        }
        //完成原本任务
        this.apply(taskEntity.getId(), addSignVo.getOperator(), addSignVo.getComment());
        return Result.success();
    }
}
